home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2005 June
/
ccd0605.iso
/
Software
/
Freeware
/
Programare
/
highlight
/
highlight-W32GUI-2.2-10b-Setup.exe
/
{app}
/
src
/
dirstream.h
< prev
next >
Wrap
C/C++ Source or Header
|
2004-02-01
|
11KB
|
371 lines
/////////////////////////////////////////////////////////////////////////////
// file : dirstream.h
// copyright : (C) 2002 by Benjamin Kaufmann
// email : hume@c-plusplus.de
// internet : http://bens.c-plusplus.info/
//
// Eine Klasse die das Browsen durch Verzeichnisse erlaubt. Dank des
// Stream-Interface ist die Klasse intuitiv bedienbar. Neben der eigentlichen
// Stream-Klasse enth�t diese Datei au�rdem noch einen DirStream-Iterator.
// Durch diesen Input-Iterator knnen DirStream-Objekte mit den Algorithmen
// der C++ Standardbibliothek verbunden werden.
//
// Die Klasse ist so konzipiert, dass sie auf verschiedenen Platformen
// eingesetzt werden kann. Fr das tats�hliche Browsing werden unter POSIX-
// kompatiblen Systemen die Funktionen opendir, readdir und closedir verwendet.
//
// Auf Win32-Platformen verwendet diese Klasse Wrapper-Funktionen
// von Kevlin Henney. Dieser Wrapper basieren auf den den Funktionen _findfirst,
// _findnext und _findclose.
// http://www.two-sdg.demon.co.uk/curbralan/code/dirent/dirent.html
//
// Die ursprngliche Idee fr diesen DirStream stammt aus dem Artikel
// "Promoting Polymorphism" von Kevlin Henney.
// http://www.appdevadvisor.co.uk/Downloads/ada5_8/Henney5_8.pdf
//
/////////////////////////////////////////////////////////////////////////////
//
/****************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
****************************************************************************/
#ifndef DIR_STREAM__H_INCLUDED
#define DIR_STREAM__H_INCLUDED
#ifdef _MSC_VER
# define for if(0);else for
# pragma warning(disable:4786)
# define HAS_STD_ITERATOR
#endif
#include <string>
#include <iterator>
#include <algorithm>
#include <cctype>
namespace DIRSTREAM
{
struct AllDirs
{
bool operator() (const char*) {return true;}
};
struct AllFiles
{
bool operator() (const char*, bool) {return true;}
};
template <class F, class D> class DirStreamImpl; // Implementationsklasse
template
<
class FileSelect, // Wird fr jede Datei aufgerufen.
class DirSelect = AllDirs // Wird fr jede Datei aufgerufen.
>
class DirStream_t
{
public:
/**
* Konstruktor der Klasse.
* Erstellt ein neues DirStream-Objekt.
* @param DirName Name des zu durchwandernden Verzeichnisses
* @param Recurse Unterverzeichnisse bercksichtigen ja/nein
* @param FSelect Funktion(sobjekt) das fr jede Datei aufgerufen wird.
* Liefert die Funktion false, wird der Eintrag ignoriert.
* @param DSelect Funktion(sobjekt) das fr jedes Unterverzeichnis
* aufgerufen wird. Liefert die Funktion false,
* wird der Eintrag ignoriert.
**/
explicit DirStream_t (const char* DirName, bool Recurse = false,
const FileSelect& FSelect = FileSelect(),
const DirSelect& DSelect = DirSelect()
);
/**
* Destruktor der Klasse.
* Gibt verwendete Resourcen frei.
**/
~DirStream_t ();
/**
* Durch diesen Operator kann ein Stream-Objekt in einen void-Pointer
* umgewandelt werden. Dieser kann dann gegen NULL geprft werden.
* Dadurch werden also Ausdrcke wie if (Stream) mglich.
**/
operator const void* () const;
/**
* �er diesen Operator wird der n�hste Eintrag des Verzeichnisses
* eingelesen.
* @param Name Bezeichnung des aktuellen Verzeichniseintrags.
* @pre Ein Verzeichnis wurde geffnet.
* @post Name enth�t den aktuellen Verzeichniseintrag. Existiert
* kein solche Eintrag, liefert der Vergleich *this == 0
* true und der Wert von Name ist undefiniert.
**/
DirStream_t& operator >> (std::string& Name);
/**
* �fnet das Verzeichnis mit dem Namen DirName und macht damit
* ein erneutes browsing mglich.
* @see DirStream_t
**/
bool open (const char* DirName, bool Recurse = false,
const FileSelect& FSelect = FileSelect(),
const DirSelect& DSelect = DirSelect()
);
/// Liefert true, falls ein Verzeichnis erfolgreich geffnet wurde.
bool is_open () const;
/**
* Liefert true, falls der aktuelle Verzeichniseintrag ein Verzeichnis ist.
* @pre IsOpen liefert true
* @post Beantwortet die Frage, ob der aktuelle Eintrag ein Verzeichnis ist.
**/
bool directory () const;
private:
// Streamobjekte knnen nicht kopiert werden, da diese
// Operation keinen Sinn macht.
DirStream_t(const DirStream_t&);
DirStream_t& operator=(const DirStream_t&);
DirStreamImpl<FileSelect, DirSelect>* m_pImpl;
};
/**
* @class DirStream_tIterator
* @brief Iterator-Klasse fr DirStream_t-Objekte.
*
* Dieser Iterator der Kategorie-Input-Iterator ermglicht die
* Verbindung von DirStream-Objekten mit den Algorithmen der
* Standardbibliothek.
**/
template <class FS, class DS = AllDirs>
class DirStream_tIterator
#ifdef HAS_STD_ITERATOR
: public std::iterator<std::input_iterator_tag, std::string>
#endif
{
// Wer std::iterator nicht hat, muss selbst fr die bentigten
// typedefs sorgen.
#ifndef HAS_STD_ITERATOR
typedef std::input_iterator_tag iterator_category;
typedef std::string value_type;
typedef ptrdiff_t difference_type;
typedef std::string* pointer;
typedef std::string& reference;
#endif
public:
/// Der Standard-Ctor erstellt einen Ende-Iterator.
DirStream_tIterator() : m_Stream(0){}
/**
* Dieser Ctor erstellt einen Iterator mit dem durch ein Verzeichnis
* iteriert werden kann. Ein solcher Iterator sollte immer gegen einen
* Ende-Iterator getestet werden.
**/
explicit DirStream_tIterator(DirStream_t<FS, DS>& Dir) : m_Stream(&Dir)
{
*m_Stream >> m_CurrFile;
}
// Implementation des Interface eines Input-Iterators
const std::string& operator*() const
{
return m_CurrFile;
}
const std::string* operator->() const
{
return &m_CurrFile;
}
DirStream_tIterator& operator++()
{
if(m_Stream) *m_Stream >> m_CurrFile;
return *this;
}
DirStream_tIterator operator++(int)
{
DirStream_tIterator Ret = *this;
++*this;
return Ret;
}
/**
* Dieser Vergleichsoperator eigent sich nicht zum Vergleich zweier
* beliebiger DirStream_tIteratoren. Vielmehr soll mit ihm lediglich
* ein Vergleich mit einem Ende-Iterator durchgefhrt werden.
**/
bool operator==(const DirStream_tIterator& rhs) const
{
return IsEnd () && rhs.IsEnd();
}
/**
* @see operator==
**/
bool operator!=(const DirStream_tIterator& rhs) const
{
return !IsEnd()||!rhs.IsEnd();
}
private:
bool IsEnd() const
{
return !m_Stream ||!*m_Stream;
}
std::string m_CurrFile;
DirStream_t<FS, DS>* m_Stream;
};
}
#include "dirstreamimpl.inl" // <- Implementationsdatei
// typedefs und ntzliche Funkionsobjekte
namespace DIRSTREAM
{
struct NoCurNoParent
{
bool operator() (const char* Name, bool)
{
std::string Temp(Name);
return Temp != "." && Temp != "..";
}
};
struct SelectOnlyDirs
{
bool operator() (const char* Name, bool IsDir)
{
return IsDir && strcmp(Name, ".") && strcmp(Name, "..");
}
};
// Dieses Funktionsobjekt w�lt nur Eintr�e eines Verzeichnisses aus,
// die dem Parameter Pattern entsprechen.
// Untersttzte Wildcards: * und ?
// * : 0 oder beliebig viele Zeichen
// ? : genau ein Zeichen
struct FileSelector
{
FileSelector(const char* Pattern, bool IgnoreCase = false) :
m_Pattern(Pattern), m_IgnoreCase(IgnoreCase),
m_HasWildCard1(false), m_HasWildCard2(false)
{
if (m_IgnoreCase)
{
#ifdef _MSC_VER
std::transform(m_Pattern.begin(), m_Pattern.end(), m_Pattern.begin(), tolower);
#else
std::transform(m_Pattern.begin(), m_Pattern.end(), m_Pattern.begin(),
/*std::*/tolower);
#endif
}
if (m_Pattern.find('*') != std::string::npos) m_HasWildCard1 = true;
if (m_Pattern.find('?') != std::string::npos) m_HasWildCard2 = true;
}
bool operator() (const char* FN, bool)
{
std::string FileName(FN);
if (m_Pattern.empty() || FileName.empty()) return false;
std::string::size_type PattSize = m_Pattern.length();
std::string::size_type FileNameSize = FileName.length();
std::string::size_type FileRun = 0;
std::string::size_type PattRun = 0;
if (!m_HasWildCard1 && PattSize != FileNameSize) return false;
if (m_IgnoreCase)
{
#ifdef _MSC_VER
std::transform(FileName.begin(), FileName.end(), FileName.begin(), tolower);
#else
std::transform(FileName.begin(), FileName.end(), FileName.begin(), /*std::*/tolower);
#endif
}
if (!m_HasWildCard1 && !m_HasWildCard2) return m_Pattern == FileName;
bool LastIsStar = (*m_Pattern.rbegin() == '*') ? true : false;
while (PattRun < PattSize && FileRun < FileNameSize)
{
if (m_Pattern[PattRun] == '*')
{ // * bedeutet 0 oder beliebig viele Zeichen.
// Es wird jetzt das n�hste relevante Zeichen von
// Pattern gesucht. Danach wird geprft, ob FileName
// dieses Zeichen enth�t.
PattRun = m_Pattern.find_first_not_of("*?", PattRun);
// Nach dem Stern folgt kein weiteres relevantes Zeichen
// FileName passt also auf jeden Fall in das Pattern.
if (PattRun == std::string::npos) return true;
char NextChar = m_Pattern[PattRun];
FileRun = FileName.find(NextChar, FileRun);
// FileName enth�t das n�hste relevante Zeichen von
// Pattern nicht. Demzufolge wollen wir diesen Eintrag
// nicht.
if (FileRun == std::string::npos) return false;
}
if (m_Pattern[PattRun] == '?')
{ // ? bedeutet genau ein Zeichen. Also wird auch genau ein
// Zeichen ignoriert.
++PattRun;
++FileRun;
continue;
}
if (m_Pattern[PattRun++] != FileName[FileRun++]) return false;
}
// Pattern und Filename waren bis auf das letzte Zeichen gleich.
// Da das letzte Zeichen von Pattern aber ein * ist und dieses
// ja auch fr 0 Zeichen steht, liefere true.
if (PattRun < PattSize && FileRun == FileNameSize && LastIsStar) return true;
// FileName und Pattern stimmen nur ber ein, wenn alle Zeichen
// verglichen wurden.
return (PattRun == PattSize && FileRun == FileNameSize);
}
private:
std::string m_Pattern;
bool m_IgnoreCase;
bool m_HasWildCard1;
bool m_HasWildCard2;
};
// und noch zwei typedefs fr die Bequemlichkeit
typedef DirStream_t<NoCurNoParent, AllDirs> DirStream;
typedef DirStream_tIterator<NoCurNoParent, AllDirs> DirStreamIterator;
}
#endif